iT邦幫忙

2025 iThome 鐵人賽

DAY 3
0
Modern Web

30 天掌握 React & Next.js:從基礎到面試筆記系列 第 3

Day 3:React Component 的生命週期

  • 分享至 

  • xImage
  •  

當我們在寫 React 時, 一個 component 是怎麼「出生 → 更新 → 死亡」的?
這段過程就叫做 生命週期 (Lifecycle)
理解生命週期,不只可以幫助我們正確放置程式邏輯,也能避免常見的錯誤,例如 API 被打爆、memory leak。

生命週期是什麼?

React component 的生命週期分三段:

  1. Mount(掛載):第一次出現在 DOM
  2. Update(更新):state/props 改變 → 重新 render
  3. Unmount(卸載):從畫面上移除

Class 用 lifecycle methods;Function 用 Hooks 來表達同一件事。

Class Component 的生命週期

✅ 「初始化 state」應發生在 render 之前

  • constructorclass field 上給初始值:
class Example extends React.Component {
  // 正確:這裡才是初始化 state 的時機
  state = { message: "Hello" };

  render() { return <h1>{this.state.message}</h1>; }
}

componentDidMount

  • 時機:首次 render 並且 DOM 已掛載 後執行
  • 用途:啟動副作用(fetch/訂閱/DOM 操作)
  • 更正:這裡不是「初始化 state」的最佳時機。若在這裡 setState,會觸發第二次 render,有機會造成畫面跳動
class Example extends React.Component {
  state = { message: "Hello" };
  componentDidMount() {
    // 這是「掛載後更新」,不是初始化
    this.setState({ message: "Mounted!" });
  }
}

componentDidUpdate(prevProps, prevState)

  • 時機:當 props 或 state 改變觸發重新渲染後,React 已經把最新的變更更新到真實 DOM,並且畫面顯示完成,這時候就會執行 componentDidUpdate
  • 用途:針對 特定 變化做事(需比較 prev 值)
  • 重點:不要無條件 setState,否則會陷入無限迴圈
componentDidUpdate(prevProps) {
  if (this.props.userId !== prevProps.userId) {
    this.fetchUser(this.props.userId);
  }
}

componentWillUnmount

  • 時機:卸載前
  • 用途:清理副作用(clearInterval、移除事件監聽、關閉 WebSocket…)以避免 memory leak

Function Component 與 Hooks

Function component 同樣經歷 mount/update/unmount,但用 Hooks 寫:

  • 初始化 state:在 useState初始值(或 lazy initializer)
function Example() {
  const [message] = React.useState(() => "Hello"); // 這裡才是初始化
  return <h1>{message}</h1>;
}
  • 掛載後/依賴變更後的副作用useEffect
// 掛載後執行一次(相當於 didMount)
useEffect(() => {
  fetch("/api/data").then(/* ... */);
}, []);

// 依賴改變時執行(相當於 didUpdate, 注意:首次掛載也會跑一次)
useEffect(() => {
  console.log("count changed:", count);
}, [count]);

// 卸載時清理(相當於 willUnmount)
useEffect(() => {
  const id = setInterval(/* ... */);
  return () => clearInterval(id);
}, []);

常見錯誤與修正

1) 在 render 階段做副作用

  • 例如直接 fetch()、操作 DOM、setTimeout
  • 影響:render 變慢、每次 re-render 又重跑、StrictMode 下更糟
  • 改成:把副作用放進 useEffect / lifecycle,render 只計算 UI

2) 忘記清理副作用

  • setInterval、事件監聽、WebSocket 沒清 → memory leak
  • 改成:在 componentWillUnmountuseEffectreturn 函式 清理
  • setTimeout 多半會自動結束,但若會在 unmount 後觸發 setState,也應清理或取消

3) componentDidUpdate 無條件 setState

  • 造成 re-render 迴圈
  • 改成:比較 prevProps/prevState 再決定是否更新

實務建議(把事放在對的位置)

  • 初始化 state:constructor / class field(Class),useState 初始值(Function)
  • 副作用componentDidMount / useEffect(抓資料、訂閱、DOM 操作)
  • 變更後反應componentDidUpdate + 比較 prev 值,或 useEffect([deps])
  • 清理componentWillUnmountuseEffect 的 return

原則:render 保持純粹(UI = f(state, props));和外界互動的一切(I/O、訂閱、計時器、DOM),都交給 effect 階段。

面試回答模板

The lifecycle of a React component describes the stages from mount to update to unmount.
In class components, we have methods like componentDidMount, componentDidUpdate, and componentWillUnmount.
In function components, we use useEffect to handle these phases: an empty dependency array works like componentDidMount, a dependency array works like componentDidUpdate, and the return function acts like componentWillUnmount.
A common mistake is placing side effects inside render, which causes unnecessary work. Instead, we always put side effects in useEffect and clean them up properly to avoid memory leaks.

中文

React 元件的生命週期,就是從「被掛載(mount)」→「更新(update)」→「被移除(unmount)」的過程。
Class Component 裡,有一些方法可以處理這些階段,例如:componentDidMountcomponentDidUpdatecomponentWillUnmount
Function Component 裡,則是用 useEffect 來完成:

  • 空的依賴陣列([])就像 componentDidMount(只在掛載後跑一次)。
  • 帶有依賴的陣列([deps])就像 componentDidUpdate(依賴改變時跑)。
  • useEffect 裡的 return function,則像 componentWillUnmount(卸載前清理)。
    常見的錯誤是把 副作用直接寫在 render 裡,這會造成多餘的操作。正確做法是把副作用放進 useEffect,並記得清理,這樣才能避免記憶體洩漏。

總結

  • 「初始化 state」≠ componentDidMount;初始化應該在 render 前 完成。
  • componentDidMount / useEffect([]) 是用來「掛載後做副作用」。
  • componentDidUpdate / useEffect([deps]) 用來「變更後做事」,要加條件避免迴圈。
  • 卸載時記得清理副作用。
  • 讓 render 階段保持純:同樣的 props/state → 同樣的 UI。

上一篇
Day 2:什麼是 JSX?
下一篇
Day 4 : React 中的 Virtual DOM 解決了什麼問題
系列文
30 天掌握 React & Next.js:從基礎到面試筆記4
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言